查看原文
其他

RecyclerView实现拖动排序和滑动删除功能

jzman 躬行之 2022-08-26

RecyclerView 的拖动排序需要借助一下 ItemTouchHelper 这个类,ItemTouchHelper 类是 Google 提供的一个支持 RecyclerView 滑动和拖动的一个使用类,下面使用该类实现 RecyclerView 的滑动删除和拖动排序功能。首先大概介绍一下 ItemTouchHelper 的一个内部抽象类  Callback 。

ItemTouchHelper.Callback

该类是ItemTouchHelper类中的一个静态抽象类,作用主要是将ItemTouchHelper 与自己的应用联系在一起,让开发者通过 ViewHolder 控制每一个 View 的具体行为,接收用户的事件回调。该类里面有三个抽象方法:getMovementFlags、onMove、onSwiped。也是开发中经常要是用的。

getMovementFlags

该方法返回一个 Flags 表示Item的三种状态状态:idle(空闲)、 swiping(滑动)、dragging(拖动),根据 RecyclerView 不同的布局管理器,设置不同的滑动、拖动方向,一般使用 makeMovementFlags(int dragFlags, int swipeFlags)方法返回,dragFlags 表示拖动的方向,swipeFlags 表示滑动的方向。

1public abstract int getMovementFlags(RecyclerView recyclerView, ViewHolder viewHolder);

onMove

当 ItemTouchHelper 拖动一个 Item 时该方法将会被回调,Item 将从旧的位置移动到新的位置,如果不拖动这个方法将从来不会调用,返回 true 表示 Item 已经被移动到新的位置。

1public abstract boolean onMove(RecyclerView recyclerView, ViewHolder viewHolder, ViewHolder target);

onSwiped

当 Item 滑动的时候调用,如果不滑动该方法不会被调用,可通过 direction 做相应的判断执行某些操作。

1public abstract void onSwiped(ViewHolder viewHolder, int direction);

此外经常使用的方法有 onSelectedChanged、clearView等方法。

onSelectedChanged

当 item 由静止状态变为滑动或拖动状态时调用此方法,可通过 actionState 判断 Item 在哪种状态下执行某些操作,重写该方法时必须调用其父类的该方法。

1public void onSelectedChanged(ViewHolder viewHolder, int actionState) {
2        if (viewHolder != null) {
3            sUICallback.onSelected(viewHolder.itemView);
4        }
5}

clearView

当与用户交互结束或相关动画完成之后该方法被调用。

1public void clearView(RecyclerView recyclerView, ViewHolder viewHolder) {
2        sUICallback.clearView(viewHolder.itemView);
3}

RecyclerView实现拖动排序

RecyclerView的拖动排序需要借助一个 android.support.v7.widget.helper.ItemTouchHelper 这个类来实现,拖动排序重点是在接口里面的 onMove(int fromPosition, int toPosition) 方法,其在 GridAdapter 中的具体实现参考如下:

1@Override
2public void onMove(int fromPosition, int toPosition) {
3    if (fromPosition < toPosition) {
4        for (int i = fromPosition; i < toPosition; i++) {
5            Collections.swap(list, i, i + 1);
6        }
7    } else {
8        for (int i = fromPosition; i > toPosition; i--) {
9            Collections.swap(list, i, i - 1);
10        }
11    }
12    notifyItemMoved(fromPosition, toPosition);
13}

RecyclerView 实现侧滑删除

RecyclerView 的拖动排序需要借助一个 android.support.v7.widget.helper.ItemTouchHelper 这个类来实现,侧滑删除重点是在接口中的 onSwiped(int position),其在 GridAdapter 中的具体实现参考如下:

1 @Override
2 public void onSwiped(int position) {
3     Log.i("drag","onSwiped");
4     list.remove(position);
5     notifyItemRemoved(position);
6 }  

参考代码

ItemTouchHelper.Callback 的实现类

 1/**
 2 * Created by jzman on 2017/5/17 0015.
 3 */

 4public class ItemTouchCallBack extends ItemTouchHelper.Callback {
 5    private static final String TAG = "drag";
 6    private OnItemTouchListener onItemTouchListener;
 7
 8    public void setOnItemTouchListener(OnItemTouchListener onItemTouchListener) {
 9        this.onItemTouchListener = onItemTouchListener;
10    }
11
12    /**
13     * 根据 RecyclerView 不同的布局管理器,设置不同的滑动、拖动方向
14     * 该方法使用 makeMovementFlags(int dragFlags, int swipeFlags) 方法返回
15     * 参数: dragFlags:拖动的方向
16     *      swipeFlags:滑动的方向
17     * @param recyclerView
18     * @param viewHolder
19     * @return
20     */

21    @Override
22    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
23        Log.i(TAG,"getMovementFlags");
24        if (recyclerView.getLayoutManager() instanceof GridLayoutManager ||
25                recyclerView.getLayoutManager() instanceof StaggeredGridLayoutManager){
26            //此处不需要进行滑动操作,可设置为除4和8之外的整数,这里设为0
27            //不支持滑动
28            return makeMovementFlags(ItemTouchHelper.UP | ItemTouchHelper.DOWN |
29                                   ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT, 0 );
30        }else {
31            //如果是LinearLayoutManager则只能向上向下滑动,
32            //此处第二个参数设置支持向右滑动
33            return makeMovementFlags(ItemTouchHelper.UP   | ItemTouchHelper.DOWN , ItemTouchHelper.RIGHT );
34        }
35    }
36
37    /**
38     * 当 ItemTouchHelper 拖动一个Item时该方法将会被回调,Item将从旧的位置移动到新的位置
39     * 如果不拖动这个方法将从来不会调用,返回true表示已经被移动到新的位置
40     * @param recyclerView
41     * @param viewHolder
42     * @param target
43     * @return
44     */

45    @Override
46    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
47        Log.i(TAG,"onMove");
48        int fromPosition = viewHolder.getAdapterPosition();
49        int toPosition   = target.getAdapterPosition();
50        onItemTouchListener.onMove(fromPosition,toPosition);
51        return true;
52    }
53
54    /**
55     * 当Item被滑动的时候被调用
56     * 如果你不滑动这个方法将不会被调用
57     * @param viewHolder
58     * @param direction
59     */

60    @Override
61    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
62        Log.i(TAG,"onSwiped");
63        //此处是侧滑删除的主要代码
64        int position = viewHolder.getAdapterPosition();
65        onItemTouchListener.onSwiped(position);
66    }
67
68    /**
69     * 当Item被滑动、拖动的时候被调用
70     * @param viewHolder
71     * @param actionState
72     */

73    @Override
74    public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
75        Log.i(TAG,"onSelectedChanged");
76        //...
77        super.onSelectedChanged(viewHolder, actionState);
78    }
79
80    /**
81     * 当与用户交互结束或相关动画完成之后被调用
82     * @param recyclerView
83     * @param viewHolder
84     */

85    @Override
86    public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
87        Log.i(TAG,"clearView");
88        //...
89        super.clearView(recyclerView, viewHolder);
90    }
91
92    /**
93     * 移动交换数据的更新监听
94     */

95    public interface OnItemTouchListener {
96        //拖动Item时调用
97        void onMove(int fromPosition, int toPosition);
98        //滑动Item时调用
99        void onSwiped(int position);
100    }
101}

Adapter的实现

 1/**
 2 * Created by jzman on 2017/05/17 0009.
 3 * RecycleView的Adapter
 4 */

 5public class GridAdapter extends RecyclerView.Adapter<GridAdapter.DataViewHolder> implements View.OnClickListener,ItemTouchCallBack.OnItemTouchListener {
 6    private Context context;
 7    private List<SimpleTitleGrid> list;
 8
 9    public GridAdapter(Context context, List<SimpleTitleGrid> list) {
10        this.context = context;
11        this.list = list;
12    }
13
14    /**
15     * 创建ViewHolder
16     * @param parent
17     * @param viewType
18     * @return
19     */

20    @Override
21    public DataViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
22        //加载item布局文件(每一个)
23        View view = LayoutInflater.from(context).inflate(R.layout.item,null);
24
25        //为View设置单击事件
26        view.setOnClickListener(this);
27        DataViewHolder viewHolder = new DataViewHolder(view);
28
29        //使用代码设置宽高(xml布局设置无效时)
30        view.setLayoutParams(new RecyclerView.LayoutParams(
31                ViewGroup.LayoutParams.MATCH_PARENT,
32                ViewGroup.LayoutParams.WRAP_CONTENT));
33        return viewHolder;
34    }
35
36    /**
37     * 绑定数据
38     * @param holder
39     * @param position
40     */

41    @Override
42    public void onBindViewHolder(DataViewHolder holder, int position) {
43        //设置每一个Item的高度
44        holder.textView.setText(list.get(position).getTitle());
45    }
46
47    /**
48     * 选项总数
49     * @return
50     */

51    @Override
52    public int getItemCount() {
53        return list.size();
54    }
55
56    /**
57     * 单击事件
58     * @param v
59     */

60    @Override
61    public void onClick(View v) {
62        if(onItemClickListener!=null){
63            int position = recyclerView.getChildAdapterPosition(v);
64            //程序执行到此,会执行该方法的具体实现
65            onItemClickListener.onItemClick(recyclerView,v,position,list.get(position));
66        }
67    }
68
69    @Override
70    public void onMove(int fromPosition, int toPosition) {
71        if (fromPosition < toPosition) {
72            for (int i = fromPosition; i < toPosition; i++) {
73                Collections.swap(list, i, i + 1);
74            }
75        } else {
76            for (int i = fromPosition; i > toPosition; i--) {
77                Collections.swap(list, i, i - 1);
78            }
79        }
80        notifyItemMoved(fromPosition, toPosition);
81    }
82
83    @Override
84    public void onSwiped(int position) {
85        Log.i("drag","onSwiped");
86        list.remove(position);
87        notifyItemRemoved(position);
88    }
89
90    /**
91     *  RecycleView中针对ViewHolder来实现
92     */

93    public static class DataViewHolder extends RecyclerView.ViewHolder {
94        TextView textView;
95        public DataViewHolder(View itemView) {
96            super(itemView);
97            textView = (TextView) itemView.findViewById(R.id.tv_grid);
98        }
99    }
100    private RecyclerView recyclerView;
101    private  OnItemClickListener onItemClickListener;
102    public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
103        this.onItemClickListener = onItemClickListener;
104    }
105    /**
106     * 设计recycleView选项单击事件的回调接口(给外面使用)
107     * 参考ListView选项单击事件方法
108     */

109    public interface OnItemClickListener{
110        //参数(父组件,点击的View,位置,这里可能是某个对象的id或对象/这里不需要)
111        void onItemClick(RecyclerView recyclerView, View view, int position, SimpleTitleGrid obj);
112    }
113    /**
114     *   将RecycleView附加到Adapter上
115     */

116    @Override
117    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
118        super.onAttachedToRecyclerView(recyclerView);
119        this.recyclerView= recyclerView;
120    }
121    /**
122     *   将RecycleView从Adapter解除
123     */

124    @Override
125    public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
126        super.onDetachedFromRecyclerView(recyclerView);
127        this.recyclerView = null;
128    }
129}

MainActivity

1/**
2 * Created by jzman on 2017/05/17 0029.
3 * RecycleView的Adapter
4 */

5public class MainActivity extends AppCompatActivity implements GridAdapter.OnItemClickListener{
6    private RecyclerView rv_user;
7    private GridAdapter adapter;
8
9    @Override
10    protected void onCreate(Bundle savedInstanceState) {
11        super.onCreate(savedInstanceState);
12        setContentView(R.layout.activity_main);
13        initView();
14    }
15
16    private void initView() {
17        rv_user = (RecyclerView) findViewById(R.id.rv_user);
18        adapter = new GridAdapter(this, DataUtils.getUserGrids());
19
20        ItemTouchCallBack touchCallBack = new ItemTouchCallBack();
21        touchCallBack.setOnItemTouchListener(adapter);
22        ItemTouchHelper itemTouchHelper = new ItemTouchHelper(touchCallBack);
23
24        rv_user.setLayoutManager(new GridLayoutManager(this,3));
25//        rv_user.setLayoutManager(new LinearLayoutManager(this));
26        rv_user.setAdapter(adapter);
27        itemTouchHelper.attachToRecyclerView(rv_user);
28
29        adapter.setOnItemClickListener(this);
30    }
31
32    @Override
33    public void onItemClick(RecyclerView recyclerView, View view, int position, SimpleTitleGrid obj) {
34        Toast.makeText(MainActivity.this, obj.getTitle(), Toast.LENGTH_SHORT).show();
35    }
36}

显示效果

GridLayoutManager 


推荐阅读:

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存